package com.fulihui.wgj.aop;

import com.fulihui.common.builder.rpc.RpcResultBuilder;
import com.fulihui.common.error.Errors;
import com.google.common.base.Stopwatch;
import com.google.common.collect.Lists;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.concurrent.TimeUnit;

/**
 * rpc统一日志处理
 *
 * @author wang_wx
 * @date 2018-08-10
 */
@Component
@Aspect
public class AspectRpcLog {

    public static final Logger LOGGER = LoggerFactory.getLogger(AspectRpcLog.class);

    @Pointcut("execution(public * com.fulihui.wgj.service..*.*ServiceImpl.*(..)))")
    public void pointCut() {
    }

    @Around("pointCut()")
    public Object handleServiceMethod(ProceedingJoinPoint pjp) {
        Stopwatch stopwatch = Stopwatch.createStarted();
        Object rpcResponse;
        try {
            LOGGER.info("-> rpc start method:{} -> request:{}", pjp.getSignature().getName(), Lists.newArrayList(pjp.getArgs()).toString());
            rpcResponse = pjp.proceed(pjp.getArgs());
            String time = stopwatch.stop().elapsed(TimeUnit.MILLISECONDS) + "ms";
            LOGGER.debug("-> rpc end ({}) method:{}-> response:{}", time, pjp.getSignature().getName(), rpcResponse);
        } catch (Throwable throwable) {
            rpcResponse = handlerException(pjp, throwable);
        }
        return rpcResponse;
    }

    /**
     * 获取方法
     *
     * @param pjp
     * @return
     */
    private Method getMethod(ProceedingJoinPoint pjp) {
        Signature signature = pjp.getSignature();
        MethodSignature methodSignature;
        if (signature instanceof MethodSignature) {
            methodSignature = (MethodSignature) signature;
            Object target = pjp.getTarget();
            try {
                return target.getClass().getMethod(methodSignature.getName(), methodSignature.getParameterTypes());
            } catch (NoSuchMethodException e) {
                LOGGER.warn("AspectRpcLog error NoSuchMethodException" + e);
            }
        }
        return null;
    }

    private Object handlerException(ProceedingJoinPoint pjp, Throwable e) {
        Object rpcResponse;
        if (e instanceof RuntimeException) {
            LOGGER.error("rpc RuntimeException, method:{}, request:{},Exception:{}", pjp.getSignature(), pjp.getArgs(), e.getMessage(), e);
            rpcResponse = RpcResultBuilder.fail(Errors.Commons.UNKNOWN_ERROR.getErrcode(), e.getMessage());
        } else {
            LOGGER.error("rpc SystemError, method:{}, request:{},Exception:{}", pjp.getSignature(), pjp.getArgs(), e.getMessage(), e);
            rpcResponse = RpcResultBuilder.fail(Errors.Commons.SYSTEM_ERROR.getErrcode(), e.getMessage());
        }
        return rpcResponse;
    }
}
